package com.evildog.workspace.gateway.fillter.factory;

import com.evildog.workspace.common.exception.ServerErrorException;
import com.evildog.workspace.gateway.enums.GatewayCustomExceptionDesc;
import com.evildog.workspace.gateway.props.IgnoreUrlsProperties;
import com.evildog.workspace.gateway.provider.ResponseProvider;
import com.evildog.workspace.gateway.util.IgnoreUtil;
import com.evildog.workspace.security.jwt.constant.TokenConstant;
import com.evildog.workspace.security.jwt.core.TokenUserInfo;
import com.evildog.workspace.security.jwt.util.JwtUtil;
import com.evildog.workspace.security.jwt.util.SecurityUtil;
import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.ObjectMapper;
import io.jsonwebtoken.Claims;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.cloud.gateway.filter.GatewayFilter;
import org.springframework.cloud.gateway.filter.GatewayFilterChain;
import org.springframework.cloud.gateway.filter.factory.AbstractGatewayFilterFactory;
import org.springframework.core.io.buffer.DataBuffer;
import org.springframework.http.HttpStatus;
import org.springframework.http.server.reactive.ServerHttpRequest;
import org.springframework.http.server.reactive.ServerHttpResponse;
import org.springframework.web.server.ServerWebExchange;
import reactor.core.publisher.Flux;
import reactor.core.publisher.Mono;

import java.nio.charset.StandardCharsets;

import static org.springframework.cloud.gateway.support.GatewayToStringStyler.filterToStringCreator;

@Slf4j
public class AuthGatewayFilterFactory extends AbstractGatewayFilterFactory<AuthGatewayFilterFactory.Config> {

    @Autowired
    private IgnoreUrlsProperties ignoreUrlsProperties;
    @Autowired
    private ObjectMapper objectMapper;
    @Autowired
    private JwtUtil jwtUtil;

    /**
     * 设置configClass
     */
    public AuthGatewayFilterFactory() {
        super(AuthGatewayFilterFactory.Config.class);
    }

    @Override
    public GatewayFilter apply(Config config) {
        return new GatewayFilter() {
            @Override
            public Mono<Void> filter(ServerWebExchange exchange,
                                     GatewayFilterChain chain) {

                String path = exchange.getRequest().getURI().getPath();
                if (IgnoreUtil.isSkip(path, ignoreUrlsProperties)) {
                    return chain.filter(exchange);
                }
                ServerHttpResponse resp = exchange.getResponse();

                String headerToken = exchange.getRequest().getHeaders().getFirst(config.header);
                String paramToken = exchange.getRequest().getQueryParams().getFirst(config.header);

                if (StringUtils.isAllBlank(headerToken, paramToken)) {
                    return unAuth(resp);
                }

                String authHead = StringUtils.isBlank(headerToken) ? paramToken : headerToken;

                // 根据token解析出用户信息
                String token = jwtUtil.getToken(authHead);
                Claims claims = jwtUtil.parseJWT(token);
                if (claims == null) {
                    return unAuth(resp);
                }

                TokenUserInfo user = SecurityUtil.getUser(claims);
                if (user == null) {
                    return unAuth(resp);
                }

                // TODO 查询用户信息，查看是否禁用，加入黑名单等

                // 添加用户信息头
                try {
                    ServerHttpRequest host = exchange.getRequest().mutate()
                            .header(TokenConstant.USER_INFO_HEADER, objectMapper.writeValueAsString(user)).build();
                    ServerWebExchange build = exchange.mutate().request(host).build();
                    return chain.filter(build);
                } catch (JsonProcessingException e) {
                    log.error(e.getMessage(), e);
                    throw new ServerErrorException(GatewayCustomExceptionDesc.JSON_PARSE_USER_ERROR);
                }
            }

            @Override
            public String toString() {
                return filterToStringCreator(AuthGatewayFilterFactory.this).toString();
            }
        };
    }

    private Mono<Void> unAuth(ServerHttpResponse resp) {
        resp.setStatusCode(HttpStatus.UNAUTHORIZED);
        resp.getHeaders().add("Content-Type", "application/json;charset=UTF-8");
        String result;
        try {
            result = objectMapper.writeValueAsString(ResponseProvider.unAuth());
        } catch (JsonProcessingException e) {
            log.error(e.getMessage(), e);
            throw new ServerErrorException(GatewayCustomExceptionDesc.JSON_PARSE_ERROR);
        }
        DataBuffer buffer = resp.bufferFactory().wrap(result.getBytes(StandardCharsets.UTF_8));
        return resp.writeWith(Flux.just(buffer));
    }


    public static class Config {
        /**
         * 认证头
         */
        private String header;

        public String getHeader() {
            return header;
        }

        public void setHeader(String header) {
            this.header = header;
        }
    }
}
